home *** CD-ROM | disk | FTP | other *** search
/ Amiga Aktuell / Amiga Aktuell.iso / amiga-aktuell / games / adventure / playmud-1.9 / doshndlfront.mod < prev    next >
Text File  |  1996-09-05  |  14KB  |  470 lines

  1. MODULE DosHndlFront;
  2.  
  3. (*---------------------------------------------------------------------------
  4. ** Copyright © 1992-1996 by Lars Düning  -  All rights reserved.
  5. ** Permission granted for non-commercial use.
  6. **---------------------------------------------------------------------------
  7. ** A simple string oriented interface to a(ny) stream handler for PlayMud,
  8. ** featuring asynchronous reads.
  9. ** When using as console, it's most useful with ConMan in non-blocking mode.
  10. **---------------------------------------------------------------------------
  11. ** Oberon: Amiga-Oberon v3.00, F. Siebert / A+L AG
  12. **---------------------------------------------------------------------------
  13. ** 10-May-92 [lars]
  14. ** 02-Apr-93 [lars] adapted for Oberon 3.00
  15. ** 03-May-93 [lars] Nonexistance of CNN: generates no requester anymore.
  16. ** 06-Sep-93 [lars] The current console can be opened explicitely.
  17. ** 10-Oct-93 [lars] Source reorganisation.
  18. ** 12-Nov-93 [lars] Added some sensitivity of g.verbosity
  19. ** 25-Feb-94 [lars] Writes weren't asynchronous, now they are.
  20. ** 02-Jan-96 [lars] currentCon moved into Global
  21. ** 01-May-96 [lars] CNN: is no longer tried.
  22. **                  Added attribute "/CLOSE" to default CON: console.
  23. **---------------------------------------------------------------------------
  24. *)
  25.  
  26. (* GarbageCollector- SmallCode SmallData *)
  27.  
  28. IMPORT
  29.   (* $IF Debug *) Debug, (* $END *)
  30.   g:Global,
  31.   d:Dos, e:Exec, ExecSupport, i:Intuition,
  32.   io, ol:OberonLib, str:Strings, s:SYSTEM;
  33.  
  34. (*-------------------------------------------------------------------------*)
  35.  
  36. TYPE
  37.   String = UNTRACED POINTER TO ARRAY OF CHAR;
  38.  
  39.   WritePacketPtr = UNTRACED POINTER TO WritePacket;
  40.   WritePacket = STRUCT
  41.     (pkt : d.StandardPacket)
  42.     txt : String;
  43.   END;
  44.  
  45. VAR
  46.   con          : d.FileHandlePtr;
  47.   window       : i.WindowPtr;   (* Pointer to Console Window if any *)
  48.   replyPort    : e.MsgPortPtr;  (* Replyport for synchronous messages to AExpress *)
  49.   winSig       : SHORTINT;      (* Signal from window *)
  50.  
  51. (*-------------------------------------------------------------------------*)
  52. PROCEDURE ReUseStdPacket ( packet : d.StandardPacketPtr;
  53.                            port : e.MsgPortPtr; type : LONGINT;
  54.                            arg1, arg2, arg3 : LONGINT
  55.                           );
  56. BEGIN
  57.   IF packet # NIL THEN
  58.     packet.msg.node.name := s.ADR(packet.pkt);
  59.     packet.msg.replyPort := port;
  60.     packet.pkt.link := s.VAL(e.MessagePtr, packet);
  61.     packet.pkt.port := packet.msg.replyPort;
  62.     packet.pkt.type := type;
  63.     packet.pkt.arg1 := arg1;
  64.     packet.pkt.arg2 := arg2;
  65.     packet.pkt.arg3 := arg3;
  66.   END;
  67. END ReUseStdPacket;
  68.  
  69. (*-------------------------------------------------------------------------*)
  70. PROCEDURE CreateStdPacket (port : e.MsgPortPtr; type : LONGINT;
  71.                            arg1, arg2, arg3 : LONGINT
  72.                           ) : d.StandardPacketPtr;
  73. VAR
  74.   packet : d.StandardPacketPtr;
  75. BEGIN
  76.   NEW (packet);
  77.   ReUseStdPacket (packet, port, type, arg1, arg2, arg3);
  78.   RETURN packet;
  79. END CreateStdPacket;
  80.  
  81. (*-------------------------------------------------------------------------*)
  82. PROCEDURE GetConInfo;
  83.  
  84. (* Get the console info from the opened console stream.
  85. *)
  86.  
  87. VAR
  88.   reply : e.MessagePtr;
  89.   packet : d.StandardPacketPtr;
  90.   iData : d.InfoDataPtr;
  91.   iDataB : BPOINTER TO d.InfoData;
  92. BEGIN
  93.   (* Stream opened, now get info about it if ConsoleHandler *)
  94.   window := NIL;
  95.   IF con.type # NIL THEN
  96.     ol.New (iData, SIZE(d.InfoData));
  97.     IF iData # NIL THEN
  98.       iDataB := s.VAL(s.ADDRESS, iData);
  99.       packet := CreateStdPacket (g.readPort, d.diskInfo
  100.                                 , s.VAL(LONGINT, iDataB), 0, 0);
  101.       IF packet # NIL THEN
  102.         e.PutMsg (con.type, packet);
  103.         e.WaitPort (g.readPort);
  104.         reply := e.GetMsg(g.readPort);
  105.         IF packet.pkt.res1 # d.DOSFALSE THEN
  106.           window := s.VAL(i.WindowPtr, iData.volumeNode);
  107.         END;
  108.         DISPOSE (packet);
  109.       ELSE
  110.         io.WriteString ("Warning: Not enough mem for console info.\n");
  111.       END;
  112.       DISPOSE (iData);
  113.     ELSE
  114.       io.WriteString ("Warning: Not enough mem for console info.\n");
  115.     END;
  116.   END;
  117. END GetConInfo;
  118.  
  119. (*-------------------------------------------------------------------------*)
  120. PROCEDURE Open * (stream : ARRAY OF CHAR) : BOOLEAN; (* $CopyArrays- *)
  121.  
  122. (* Open the named stream for I/O. If no name is given, following defaults
  123. ** are tried in given order:
  124. **   CON:0/11/640/225/A-LPmud/CLOSE
  125. ** Success is returned.
  126. *)
  127.  
  128. VAR
  129.   len : LONGINT;
  130.   oldWin : i.WindowPtr;
  131.   me : d.ProcessPtr;
  132.  
  133. (* To open optional console handlers, use this sequence to suppress
  134.  * requesters:
  135.  *   oldWin := me.windowPtr;
  136.  *   me.windowPtr := s.VAL (i.WindowPtr, -1);  (* suppresses requester *)
  137.  *   con := d.Open ("CNN:/11///AmigaLPmud/c", d.newFile);
  138.  *   me.windowPtr := oldWin;
  139.  *)
  140.  
  141. BEGIN
  142.   IF con # NIL THEN
  143.     io.WriteString ("Error: Open console already exists.\n");
  144.     RETURN FALSE;
  145.   END;
  146.  
  147.   replyPort := ExecSupport.CreatePort("", 0);
  148.   IF replyPort = NIL THEN
  149.     io.WriteString("Error: Can't open replyport for console messages.\n");
  150.     RETURN FALSE;
  151.   END;
  152.  
  153.   g.currentCon := FALSE;
  154.   len := str.Length(stream);
  155.   con := NIL;
  156.   IF len = 0 THEN
  157.     me := s.VAL (d.ProcessPtr, ol.Me);
  158.     con := d.Open ("CON:/11///AmigaLPmud/CLOSE", d.newFile);
  159.     IF con # NIL THEN
  160.       IF g.verbosity # g.quiet THEN
  161.         io.WriteString ("  Console CON:/11///AmigaLPmud/CLOSE \n");
  162.       END;
  163.     ELSE
  164.       io.WriteString ("Error: Can't open any console.\n");
  165.       ExecSupport.DeletePort(replyPort); replyPort := NIL;
  166.       RETURN FALSE;
  167.     END;
  168.   ELSE
  169.     con := d.Open (stream, d.newFile);
  170.     IF con = NIL THEN
  171.       io.WriteString ("Error: Can't open ");
  172.       io.WriteString (stream);
  173.       io.WriteLn;
  174.       ExecSupport.DeletePort(replyPort); replyPort := NIL;
  175.       RETURN FALSE;
  176.     ELSIF g.verbosity # g.quiet THEN
  177.       io.WriteString ("  Console ");
  178.       io.WriteString (stream);
  179.       io.WriteLn;
  180.     END;
  181.   END;
  182.   IF ~d.IsInteractive(con) THEN (* Late, but at last.. *)
  183.     io.WriteString ("Error: Console is not interactive.\n");
  184.     s.SETREG(0, d.Close(con));
  185.     con := NIL;
  186.     ExecSupport.DeletePort(replyPort); replyPort := NIL;
  187.     RETURN FALSE;
  188.   END;
  189.  
  190.   (* Stream opened, now get info about it if ConsoleHandler *)
  191.   GetConInfo;
  192.   RETURN TRUE;
  193. END Open;
  194.  
  195. (*-------------------------------------------------------------------------*)
  196. PROCEDURE OpenCurrent * () : BOOLEAN;
  197.  
  198. (* Open the current console (either Input() or Output()) for I/O.
  199. ** Success is returned.
  200. *)
  201.  
  202. BEGIN
  203.   IF con # NIL THEN
  204.     io.WriteString ("Error: Open console already exists.\n");
  205.     RETURN FALSE;
  206.   END;
  207.  
  208.   replyPort := ExecSupport.CreatePort("", 0);
  209.   IF replyPort = NIL THEN
  210.     io.WriteString("Error: Can't open replyport for console messages.\n");
  211.     RETURN FALSE;
  212.   END;
  213.  
  214.   IF d.Input # NIL THEN
  215.     con := d.Input();
  216.     IF g.verbosity # g.quiet THEN
  217.       io.WriteString ("  Console is current input\n");
  218.     END;
  219.   ELSIF d.Output # NIL THEN
  220.     con := d.Input();
  221.     IF g.verbosity # g.quiet THEN
  222.       io.WriteString ("  Console is current output\n");
  223.     END;
  224.   ELSE
  225.     io.WriteString ("Error: No current console.\n");
  226.     ExecSupport.DeletePort(replyPort); replyPort := NIL;
  227.     RETURN FALSE;
  228.   END;
  229.   IF ~d.IsInteractive(con) THEN
  230.     io.WriteString ("Error: Console is not interactive.\n");
  231.     con := NIL;
  232.     ExecSupport.DeletePort(replyPort); replyPort := NIL;
  233.     RETURN FALSE;
  234.   END;
  235.  
  236.   g.currentCon := TRUE;
  237.   GetConInfo;
  238.   RETURN TRUE;
  239. END OpenCurrent;
  240.  
  241. (*-------------------------------------------------------------------------*)
  242. PROCEDURE Close * ();
  243.  
  244. (* Closes any open console stream *)
  245.  
  246. VAR
  247.   msg : e.MessagePtr;
  248. BEGIN
  249.   IF con = NIL THEN RETURN; END;
  250.   IF ~g.currentCon THEN s.SETREG(0, d.Close(con)); END;
  251.   con := NIL; window := NIL; g.currentCon := FALSE; winSig := -1;
  252.   IF g.verbosity # g.quiet THEN io.WriteString ("Console stream closed.\n"); END;
  253.   IF g.readPort = NIL THEN RETURN; END;
  254.   IF g.verbosity # g.quiet THEN io.WriteString ("Collecting left packets..."); END;
  255.   msg := e.GetMsg(replyPort);
  256.   WHILE msg # NIL DO msg := e.GetMsg(replyPort); END;
  257.   ExecSupport.DeletePort(replyPort); replyPort := NIL;
  258.   msg := e.GetMsg(g.readPort);
  259.   WHILE msg # NIL DO msg := e.GetMsg(g.readPort); END;
  260.   (* the mem or our msgs will be automagically freed on programs exit *)
  261.   IF g.verbosity # g.quiet THEN io.WriteString ("done.\n"); END;
  262. END Close;
  263.  
  264. (*-------------------------------------------------------------------------*)
  265. PROCEDURE FrontendSig * () : LONGSET;
  266.  
  267. (* Return the signal which is set if a message arrives from the user.
  268. ** Return -1 for no signal.
  269. ** This also sets the console window to accept closeWindow events.
  270. *)
  271.  
  272. VAR
  273.   signals : LONGSET;
  274. BEGIN
  275.   winSig := -1;
  276.   IF (con # NIL) & (window # NIL) THEN
  277.    IF window.userPort = NIL THEN signals := LONGSET{i.closeWindow};
  278.     ELSE
  279.       signals := window.idcmpFlags;
  280.       INCL(signals, i.closeWindow);
  281.     END;
  282.     i.OldModifyIDCMP (window, signals);
  283.     IF window.userPort # NIL THEN
  284.       winSig := window.userPort.sigBit;
  285.     END;
  286.   END;
  287.   signals := LONGSET{};
  288.   IF winSig # -1 THEN
  289.     INCL(signals, winSig);
  290.   END;
  291.   IF replyPort # NIL THEN
  292.     INCL(signals, replyPort.sigBit);
  293.   END;
  294.   RETURN signals;
  295. END FrontendSig;
  296.  
  297. (*-------------------------------------------------------------------------*)
  298. PROCEDURE HandleYourSig * (signals : LONGSET; VAR abort : BOOLEAN);
  299.  
  300. (* If PlayMud got a 'FrontendSig' (= a signal from the console window),
  301. ** it calls this functions and leaves it to us to handle the signal.
  302. ** If an aborting condition is detected, 'abort' is to be set to TRUE,
  303. ** else is mustn't be changed.
  304. *)
  305.  
  306. VAR
  307.   winMsg : i.IntuiMessagePtr;
  308.   pkt : WritePacketPtr;
  309. BEGIN
  310.   IF (con # NIL) & (window # NIL) & (winSig # -1) & (winSig IN signals) THEN
  311.     winMsg := e.GetMsg (window.userPort);
  312.     WHILE winMsg # NIL DO
  313.       IF i.closeWindow IN winMsg.class THEN abort := TRUE; END;
  314.       e.ReplyMsg(winMsg);
  315.       winMsg := e.GetMsg (window.userPort);
  316.     END;
  317.   END;
  318.   IF (replyPort # NIL) & (replyPort.sigBit IN signals) THEN
  319.     pkt := e.GetMsg(replyPort);
  320.     WHILE pkt # NIL DO
  321.       IF g.verbosity > g.verbose THEN io.WriteString("ConReply "); END;
  322.       DISPOSE(pkt.txt);
  323.       DISPOSE(pkt);
  324.       pkt := e.GetMsg(replyPort);
  325.     END;
  326.   END;
  327. END HandleYourSig;
  328.  
  329. (*-------------------------------------------------------------------------*)
  330. PROCEDURE Write (ch : CHAR);
  331.  
  332. (* Write a single character to console *)
  333.  
  334. VAR
  335.   packet : WritePacketPtr;
  336.   txt    : String;
  337. BEGIN
  338.   IF con = NIL THEN RETURN; END;
  339.   NEW(packet);
  340.   IF packet = NIL THEN
  341.     io.WriteString("Error: Not enough mem for packet - character discarded.\n");
  342.     RETURN;
  343.   END;
  344.   NEW(txt, 2);
  345.   IF txt = NIL THEN
  346.     io.WriteString("Error: Not enough mem for string - character discarded.\n");
  347.     DISPOSE(packet);
  348.     RETURN;
  349.   END;
  350.   packet.txt := txt;
  351.   ReUseStdPacket(packet, replyPort, d.write, con.arg1, s.ADR(packet.txt[0]), 1);
  352.   packet.txt[0] := ch;
  353.   packet.txt[1] := 0X;
  354.   e.PutMsg(con.type, packet);
  355.   IF g.verbosity > g.verbose THEN io.WriteString("ToCon "); END;
  356.   IF g.pos > 0 THEN g.writeOccured := TRUE; END;
  357. END Write;
  358.  
  359. (*-------------------------------------------------------------------------*)
  360. PROCEDURE PutString * (text : ARRAY OF CHAR; len : LONGINT); (* $CopyArrays- *)
  361.  
  362. (* Write a string of given length to console *)
  363.  
  364. VAR
  365.   txt : String;
  366.   packet : WritePacketPtr;
  367. BEGIN
  368.   IF con = NIL THEN RETURN; END;
  369.   NEW(packet);
  370.   IF packet = NIL THEN
  371.     io.WriteString("Error: Not enough mem for packet - text discarded.\n");
  372.     RETURN;
  373.   END;
  374.   NEW(txt, len+1);
  375.   IF txt = NIL THEN
  376.     io.WriteString("Error: Not enough mem for string - text discarded.\n");
  377.     DISPOSE(packet);
  378.     RETURN;
  379.   END;
  380.   packet.txt := txt;
  381.   ReUseStdPacket(packet, replyPort, d.write, con.arg1, s.ADR(packet.txt[0]), len);
  382.   str.Cut(text, 0, len, packet.txt^);
  383.   packet.txt[len] := 0X;
  384.   e.PutMsg(con.type, packet);
  385.   IF g.verbosity > g.verbose THEN io.WriteString("ToCon "); END;
  386.   IF g.pos > 0 THEN g.writeOccured := TRUE; END;
  387. END PutString;
  388.  
  389. (*-------------------------------------------------------------------------*)
  390. PROCEDURE WriteString * (text : ARRAY OF CHAR); (* $CopyArrays- *)
  391.  
  392. (* Write a null-terminated string to console *)
  393.  
  394. BEGIN
  395.   PutString(text, str.Length(text));
  396. END WriteString;
  397.  
  398. (*-------------------------------------------------------------------------*)
  399. PROCEDURE QueueRead * (packet : d.StandardPacketPtr);
  400.  
  401. (* Sends one read request for one character to console.
  402. ** If a packet is to be reused, it may be given, else NIL.
  403. ** As buffer, g.inLine[++g.pos] is given.
  404. ** This fun must be called directly after Open() once to initiate reads !
  405. *)
  406.  
  407. BEGIN
  408.   IF con = NIL THEN RETURN; END;
  409.   IF g.pos < g.MaxLineLen-3 THEN INC(g.pos); END;
  410.   IF packet # NIL THEN
  411.     ReUseStdPacket (packet, g.readPort, d.read, con.arg1, s.ADR(g.inLine[g.pos]), 1);
  412.   ELSE
  413.     packet := CreateStdPacket (g.readPort,d.read, con.arg1,s.ADR(g.inLine[g.pos]),1);
  414.   END;
  415.   IF packet # NIL THEN e.PutMsg (con.type, packet);
  416.   ELSE io.WriteString ("Error: Not enough mem for packet.\n");
  417.   END;
  418. END QueueRead;
  419.  
  420. (*-------------------------------------------------------------------------*)
  421. PROCEDURE ReadChar * () : BOOLEAN;
  422.  
  423. (* Reads in a received ReadRequest and queues up a new one.
  424. ** If the request completed a line, it will be copied in to g.line.
  425. ** If necessary, this line will be echoed.
  426. ** Returns condition "line completed".
  427. *)
  428.  
  429. VAR
  430.   packet : d.StandardPacketPtr;
  431.   rc     : BOOLEAN;
  432. BEGIN
  433.   IF con = NIL THEN RETURN FALSE; END;
  434.   rc := FALSE;
  435.   packet := e.GetMsg(g.readPort);
  436.   IF packet = NIL THEN
  437.     IF g.verbosity > g.verbose THEN
  438.       io.WriteString ("Warning: No packet arrived.\n");
  439.     END;
  440.     RETURN FALSE;
  441.   END;
  442.  
  443.   IF packet.pkt.res1 = 1 THEN
  444.     CASE g.inLine[g.pos] OF "\n", 1CX, 0X :
  445.       g.inLine[g.pos+1] := 0X;
  446.       IF g.writeOccured & ~g.noEcho THEN
  447.         WriteString ("\n"); WriteString (g.inLine);
  448.       END;
  449.       COPY(g.inLine, g.line); g.pos := -1;
  450.       g.writeOccured := FALSE;
  451.       rc := TRUE;
  452.     ELSE
  453.     END;
  454.   END;
  455.   QueueRead(packet);
  456.   RETURN rc;
  457. END ReadChar;
  458.  
  459. (*-------------------------------------------------------------------------*)
  460.  
  461. BEGIN
  462.   window := NIL;
  463.   replyPort := NIL;
  464.   winSig := -1;
  465. CLOSE
  466.   IF replyPort # NIL THEN ExecSupport.DeletePort(replyPort); END;
  467. END DosHndlFront.
  468.  
  469. (*=========================================================================*)
  470.